//
//  ViewUtils.swift
//  novelReader
//
//  Created by Ink on 2019/9/12.
//  Copyright © 2019 ChineseAll. All rights reserved.
//

import UIKit
import SnapKit
import Toast_Swift
import RxSwift

// MARK: - UINibProtocol
public protocol UINibProtocol : ClassNameProtocol,NSObjectProtocol {
    static var nib: UINib { get }
}

extension UINibProtocol {
    public static var nib: UINib {
        UINib(nibName: className, bundle: Bundle(for: self))
    }
}

extension UIView : UINibProtocol {
    
    public class func loadFromNib(name:String? = nil, bundle: Bundle = Bundle.main) -> Self {
        guard let instance = bundle.loadNibNamed(name ?? className, owner: self)?.first as? Self else {
            assertionFailure("nib error")
            return Self()
        }
        return instance
    }
}

// 添加可设置属性 支持xib
public extension UIView {
    
    @IBInspectable var cornerRadius: CGFloat {
        set {
            layer.cornerRadius = newValue
            if newValue > 0 {
                masksToBounds = true
            }
        }
        get {
            layer.cornerRadius
        }
    }
    
    @IBInspectable var maskedCorners: CACornerMask {
        set {
            layer.maskedCorners = newValue
        }
        get {
            layer.maskedCorners
        }
    }
    
    @IBInspectable var corners: UIRectCorner {
        get {
            var corners = UIRectCorner()
            if layer.maskedCorners.contains(.layerMinXMinYCorner) { corners.insert(.topLeft) }
            if layer.maskedCorners.contains(.layerMaxXMinYCorner) { corners.insert(.topRight) }
            if layer.maskedCorners.contains(.layerMinXMaxYCorner) { corners.insert(.bottomLeft) }
            if layer.maskedCorners.contains(.layerMaxXMaxYCorner) { corners.insert(.bottomRight) }
            return corners
        }
        set {
            var newMaskedCorners = CACornerMask()
            if newValue.contains(.topLeft) { newMaskedCorners.insert(.layerMinXMinYCorner) }
            if newValue.contains(.topRight) { newMaskedCorners.insert(.layerMaxXMinYCorner) }
            if newValue.contains(.bottomLeft) { newMaskedCorners.insert(.layerMinXMaxYCorner) }
            if newValue.contains(.bottomRight) { newMaskedCorners.insert(.layerMaxXMaxYCorner) }
            layer.maskedCorners = newMaskedCorners
        }
    }
    
    @IBInspectable var borderWidth: CGFloat {
        set {
            layer.borderWidth = newValue
        }
        get {
            layer.borderWidth
        }
    }
    
    @IBInspectable var borderColor: UIColor {
        set {
            layer.borderColor = newValue.cgColor
        }
        get {
            if let cgColor = layer.borderColor {
                return UIColor(cgColor: cgColor)
            }
            else {
                return .clear
            }
        }
    }
    
    @IBInspectable var masksToBounds: Bool {
        set {
            layer.masksToBounds = newValue
        }
        get {
            layer.masksToBounds
        }
    }
    
    /// 部分圆角
    ///
    /// - Parameters:
    ///   - corners: 需要实现为圆角的角，可传入多个
    ///   - radii: 圆角半径
    func corner(_ corners: UIRectCorner = .allCorners, radii: CGFloat) {
        self.corners = corners
        self.cornerRadius = radii
    }
}

//// MARK: -  UIView Shadow
//extension UIView {
//
//    func shadow(shadowOpacity: Float = 0.3, shadowOffset:CGSize = CGSize(width: 0, height: 2),shadowRadius: CGFloat = 2.0,shadowColor: UIColor = UIColor.black, inSelf: Bool = false) {
//
//        var shadowView: UIView
//
//        if inSelf == true {
//            shadowView = self
//        }
//        else {
//            shadowView = UIView()
//            shadowView.backgroundColor = UIColor.lightGray
//            shadowView.tag = 99999
//            shadowView.isUserInteractionEnabled = false
//            superview?.insertSubview(shadowView, belowSubview: self)
//            shadowView.snp.makeConstraints { make in
//                make.edges.equalTo(self)
//            }
//        }
//
//        shadowView.layer.shadowOpacity = shadowOpacity
//        shadowView.layer.shadowOffset  = shadowOffset
//        shadowView.layer.shadowRadius  = shadowRadius
//        shadowView.layer.shadowColor   = shadowColor.cgColor
//        shadowView.clipsToBounds = false
//    }
//
//    func clearShadow(){
//        let view = superview?.viewWithTag(99999)
//        if let tempView = view {
//            tempView.removeFromSuperview();
//        }
//    }
//}

// MARK: 链式
extension UIView {
    
    @discardableResult
    public func background(color: UIColor?) -> Self{
        backgroundColor = color
        return self
    }
    
}

extension UIView {

    public var size:CGSize {
        set{ frame.size = newValue }
        get{ frame.size }
    }
    
    public var origin:CGPoint {
        set{ frame.origin = newValue }
        get{ frame.origin }
    }
        
    public var height:CGFloat {
        set{ size.height = newValue }
        get{ size.height }
    }
    
    public var width:CGFloat {
        set{ size.width = newValue }
        get{ size.width }
    }
        
    public var x:CGFloat {
        set{ origin.x = newValue }
        get{ origin.x }
    }
    
    public var left:CGFloat {
        set{ x = newValue }
        get{ x }
    }
        
    public var right:CGFloat{ x + width }
    
    public var y:CGFloat{
        set{ origin.y = newValue }
        get{ origin.y }
    }
    
    public var top:CGFloat{
        set{ y = newValue }
        get{ y }
    }
        
    public var bottom:CGFloat{ y + height }
    
    public func edgesEqualToSuperview() {
        snp.makeConstraints {
            $0.edges.equalToSuperview()
        }
    }
    
    public func centerEqualToSuperview() {
        snp.makeConstraints {
            $0.center.equalToSuperview()
        }
    }
}

public extension UIView {
    func parentViewController() -> UIViewController? {
        var parentResponder: UIResponder? = self
        while parentResponder != nil {
            parentResponder = parentResponder!.next
            if let viewController = parentResponder as? UIViewController {
                return viewController
            }
        }
        return nil
    }
}

extension CACornerMask: @retroactive CaseIterable {
    public static var allCases: [CACornerMask] {
        [.layerMinXMinYCorner,.layerMaxXMaxYCorner,.layerMinXMinYCorner,.layerMaxXMaxYCorner]
    }
}

public extension UIView {
    
    //MARK: - 转图片
    func convertToImage() -> UIImage? {
        var image: UIImage?
        UIGraphicsBeginImageContextWithOptions(self.frame.size, false, UIScreen.main.scale)
        if let context = UIGraphicsGetCurrentContext() {
            layer.render(in: context)
        }
        image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

private extension UIView.AssociatedKeys {
    static var toastForbidUserInteractionEnabledKey = getZMKey()
    static var beforeToastUserInteractionEnabledKey = getZMKey()
    static var isToastActivityKey = getZMKey()
}

extension UIView {
    
    // toast 禁止用户交互
    private var toastForbidUserInteractionEnabled: Bool? {
        set { mUtilMap[AssociatedKeys.toastForbidUserInteractionEnabledKey] = newValue }
        get { mUtilMap[AssociatedKeys.toastForbidUserInteractionEnabledKey] as? Bool }
    }
    
    // toast 修改用户交互权限前的状态
    private var beforeToastUserInteractionEnabled: Bool? {
        set { mUtilMap[AssociatedKeys.beforeToastUserInteractionEnabledKey] = newValue }
        get { mUtilMap[AssociatedKeys.beforeToastUserInteractionEnabledKey] as? Bool }
    }
    
    private var isToastActivity: Bool? {
        set { mUtilMap[AssociatedKeys.isToastActivityKey] = newValue }
        get { mUtilMap[AssociatedKeys.isToastActivityKey] as? Bool }
    }

    public class func toast(_ message: String?, duration: Float = 2.5, posit:ToastPosition = .center, view: UIView? = nil) {
        let showView = view
        showView?.hideAllToasts()
        let style = ToastStyle()
        showView?.makeToast(message, duration: TimeInterval(duration), position: posit, title: nil, image: nil, style: style, completion: nil)
    }
    
    public func toast(_ message: String?, duration: Float = 2.5, posit:ToastPosition = .center) {
        UIView.toast(message, duration: duration, posit:posit, view: self)
    }
    
    public func toastActivity(posit:ToastPosition = .center, forbiduserInteractionEnabled: Bool? = nil) {
        if isToastActivity == true {
            return
        }
        isToastActivity = true
//        makeToastActivity(posit)
        makeCustomToastActivity()
        beforeToastUserInteractionEnabled = isUserInteractionEnabled
        toastForbidUserInteractionEnabled = forbiduserInteractionEnabled
        forbiduserInteractionEnabled == true ? isUserInteractionEnabled = false : nil
    }

    public func hideActivity() {
        isToastActivity = nil
//        hideToastActivity()
        hideCustomToastActivity()
        if toastForbidUserInteractionEnabled == true, let enabled = beforeToastUserInteractionEnabled {
            isUserInteractionEnabled = enabled
            beforeToastUserInteractionEnabled = nil
            toastForbidUserInteractionEnabled = nil
        }
    }
    
    private func makeCustomToastActivity() {
        zm_makeToastActivity()
    }
    
    private func hideCustomToastActivity() {
        zm_hideToastActivity()
    }
    
    static let customAtivityViewKey = "customAtivityViewKey"
    
    private func zm_makeToastActivity() {
        // sanity
        guard self[mUtil: Self.customAtivityViewKey] as? UIView == nil else { return }
        guard let toast = SDKLoader.share.customToastLottieView else { return }
        
        zm_makeToastActivity(toast)
    }
    
    private func zm_makeToastActivity(_ toast: UIView) {
        toast.alpha = 0.0
        
        self[mUtil: Self.customAtivityViewKey] = toast
        
        addSubview(toast)
        toast.centerEqualToSuperview()
        
        UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: .curveEaseOut, animations: {
            toast.alpha = 1.0
        })
    }
    
    private func zm_hideToastActivity() {
        if let toast = self[mUtil: Self.customAtivityViewKey] as? UIView {
            UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.curveEaseIn, .beginFromCurrentState], animations: {
                toast.alpha = 0.0
            }) { _ in
                toast.removeFromSuperview()
                self[mUtil: Self.customAtivityViewKey] = nil
            }
        }
    }
}

extension UIView {
    
    fileprivate struct AssociatedKeys {
        static let tapGesture = "UIView_tapGesture"
        static let UIView_control = "UIView_control"
    }
    
    @discardableResult
    public func addControllHandler(for controlEvents: UIControl.Event = .touchUpInside,customInterval:TimeInterval? = nil, _ action: ZMHandler?) -> Self {
        removeControllHandler()
        let control = UIControl()
        insertSubview(control, at: 0)
        control.ignoreInterval = false
        control.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        control.addHandler(for: controlEvents, customInterval: customInterval,action)
        mUtilWeakMap[mUtil: UIView.AssociatedKeys.UIView_control] = control
        isUserInteractionEnabled = true
        return self
    }
    
    @discardableResult
    public func removeControllHandler(for controlEvents: UIControl.Event = .allEvents) -> Self {
        if let control = mUtilWeakMap[mUtil: UIView.AssociatedKeys.UIView_control] as? UIControl {
            control.removeFromSuperview()
            mUtilWeakMap[mUtil: UIView.AssociatedKeys.UIView_control] = nil
        }
        return self
    }
    
    @discardableResult
    public func addTapHandler(_ action: ZMHandler?) -> Self {
        var singleTap: UITapGestureRecognizer?
        return addTapHandler(tapGesture: &singleTap,action)
    }
    
    @discardableResult
    public func addTapHandler(tapGesture: inout UITapGestureRecognizer?,_ action: ZMHandler?) -> Self {
        removeTapHandler()

        let tap = UITapGestureRecognizer()
        addGestureRecognizer(tap)
        tapGesture = tap

        mUtilWeakMap[mUtil: UIView.AssociatedKeys.tapGesture] = tap
        tap.rx.event.bind { _ in
            action?()
        }.disposed(by: self.rxDisposeBag)

        isUserInteractionEnabled = true
        return self
    }
    
    @discardableResult
    public func removeTapHandler() -> Self {
        if let tapGesture = mUtilWeakMap[mUtil:UIView.AssociatedKeys.tapGesture] as? UITapGestureRecognizer {
            mUtilMap[UIView.AssociatedKeys.tapGesture] = nil
            removeGestureRecognizer(tapGesture)
        }
        return self
    }
}

extension NSLayoutConstraint {
    /**
     Change multiplier constraint

     - parameter multiplier: CGFloat
     - returns: NSLayoutConstraint
    */
    public func setMultiplier(multiplier:CGFloat) -> NSLayoutConstraint {

        NSLayoutConstraint.deactivate([self])

        let newConstraint = NSLayoutConstraint(
            item: firstItem as Any,
            attribute: firstAttribute,
            relatedBy: relation,
            toItem: secondItem,
            attribute: secondAttribute,
            multiplier: multiplier,
            constant: constant)

        newConstraint.priority = priority
        newConstraint.shouldBeArchived = self.shouldBeArchived
        newConstraint.identifier = self.identifier

        NSLayoutConstraint.activate([newConstraint])
        return newConstraint
    }
}

public protocol ViewSizeProtocol: NSObjectProtocol {
    static var viewHeight : CGFloat{ get }
    static var viewSize : CGSize{ get }
}

extension ViewSizeProtocol {
    public static var viewHeight : CGFloat{ .zero }
    public static var viewSize : CGSize{ .zero }
}

public extension CAGradientLayer {
    
    enum GradientType {
        case Horizontal
        case Vertical
        case Custom(startPoint:CGPoint,endPoint:CGPoint)
        
        var value:(startPoint:CGPoint,endPoint:CGPoint) {
            switch self {
            case .Horizontal:
                return (CGPoint(x: 0, y: 0.5), CGPoint(x: 1, y: 0.5))
            case .Vertical:
                return (CGPoint(x: 0.5, y: 0), CGPoint(x: 0.5, y: 1))
            case .Custom(let startPoint, let endPoint):
                return (startPoint, endPoint)
            }
        }
    }
    
    convenience init(_ colors:[CGColor],
                     type:GradientType = .Horizontal,
                     flip:Bool = false) {
        self.init()
        self.locations = [0, 1]
        self.colors = colors
        if flip {
            self.startPoint = CGPoint(x:1-type.value.0.x,y:1-type.value.0.y)
            self.endPoint = CGPoint(x:1-type.value.1.x,y:1-type.value.1.y)
        }
        else {
            self.startPoint = type.value.0
            self.endPoint = type.value.1
        }
    }
    
    convenience init(_ colors:[UIColor],
                     type:GradientType = .Horizontal,
                     flip:Bool = false) {
        self.init(colors.map { $0.cgColor }, type:type,flip: flip)
    }
}

public protocol GradientViewProtocol {
    var gradientLayer: CAGradientLayer? { get set }
    @discardableResult
    func setGradient(_ layer: CAGradientLayer) -> Self
    @discardableResult
    func removeGradient() -> Self
    func layoutGradient()
}

public extension GradientViewProtocol where Self: UIView {
    
    var gradientLayer: CAGradientLayer? {
        set {
            gradientLayer?.removeFromSuperlayer()
            self.mUtilMap["gradientLayer"] = newValue
            if let gLayer = newValue {
                self.layer.insertSublayer(gLayer, at: 0)
            }
        }
        get {
            self.mUtilMap["gradientLayer"] as? CAGradientLayer
        }
    }
    
    @discardableResult
    func setGradient(_ glayer: CAGradientLayer) -> Self {
        backgroundColor = .clear
        gradientLayer = glayer
        if let btn = self as? UIButton {
            btn.titleLabel?.setter.apply({[weak self] view in
                self?.bringSubviewToFront(view)
            })
            btn.imageView?.setter.apply({[weak self] view in
                self?.bringSubviewToFront(view)
            })
        }
        return self
    }
    
    @discardableResult
    func removeGradient() -> Self {
        gradientLayer?.removeFromSuperlayer()
        gradientLayer = nil
        return self
    }
    
    func layoutGradient() {
        gradientLayer?.frame = self.bounds
    }
}


public extension UIView {
    /// 递归查找指定类型的子视图，支持层级深度限制
    /// - Parameters:
    ///   - type: 要查找的视图类型（如 UICollectionView.self）
    ///   - maxDepth: 最大搜索层级（nil 表示不限制，默认为 nil）
    /// - Returns: 找到的视图或 nil
    func findSubview<T: UIView>(ofType type: T.Type, maxDepth: Int? = nil) -> T? {
        return findSubview(ofType: type, currentDepth: 0, maxDepth: maxDepth)
    }
    
    private func findSubview<T: UIView>(
        ofType type: T.Type,
        currentDepth: Int,
        maxDepth: Int?
    ) -> T? {
        // 超出最大深度限制时停止搜索
        if let maxDepth = maxDepth, currentDepth >= maxDepth {
            return nil
        }
        
        // 遍历当前层级的子视图
        for subview in subviews {
            if let target = subview as? T {
                return target
            }
            // 递归搜索下一层级（深度+1）
            if let found = subview.findSubview(
                ofType: type,
                currentDepth: currentDepth + 1,
                maxDepth: maxDepth
            ) {
                return found
            }
        }
        return nil
    }
}
